package com.zhiche.wms.service.outbound.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zhiche.wms.core.supports.BaseException;
import com.zhiche.wms.core.supports.enums.TableStatusEnum;
import com.zhiche.wms.core.utils.SnowFlakeId;
import com.zhiche.wms.domain.mapper.outbound.OutboundNoticeHeaderMapper;
import com.zhiche.wms.domain.model.log.ItfImplogHeader;
import com.zhiche.wms.domain.model.log.ItfImplogLine;
import com.zhiche.wms.domain.model.outbound.OutboundNoticeHeader;
import com.zhiche.wms.domain.model.outbound.OutboundNoticeLine;
import com.zhiche.wms.dto.outbound.*;
import com.zhiche.wms.service.base.IBusinessDocNumberService;
import com.zhiche.wms.service.constant.Status;
import com.zhiche.wms.service.log.IItfImplogHeaderService;
import com.zhiche.wms.service.log.IItfImplogLineService;
import com.zhiche.wms.service.outbound.IOutboundNoticeHeaderService;
import com.zhiche.wms.service.outbound.IOutboundNoticeLineService;
import com.zhiche.wms.service.utils.CommonMethod;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 出库通知单头 服务实现类
 * </p>
 *
 * @author qichao
 * @since 2018-06-08
 */
@Service
public class OutboundNoticeHeaderServiceImpl extends ServiceImpl<OutboundNoticeHeaderMapper, OutboundNoticeHeader> implements IOutboundNoticeHeaderService {

    private static final Logger LOGGER = LoggerFactory.getLogger(OutboundNoticeHeaderServiceImpl.class);

    @Autowired
    private IBusinessDocNumberService iBusinessDocNumberService;
    @Autowired
    private IOutboundNoticeLineService noticeLineService;
    @Autowired
    private IItfImplogHeaderService implogHeaderService;
    @Autowired
    private IItfImplogLineService implogLineService;
    @Autowired
    private SnowFlakeId snowFlakeId;

    @Autowired
    private IOutboundNoticeLineService outboundNoticeLineService;


    @Override
    public Map<String, Object> saveOutboundNotice(List<OutboundNoticeParamDTO> dtos) {
        LOGGER.info("OutboundNoticeHeaderServiceImpl.saveOutboundNotice params:{}", dtos);
        Map<String, Object> exMap = Maps.newHashMap();
        StringBuilder headEx = new StringBuilder();
        StringBuilder lineEx = new StringBuilder();
        if (CollectionUtils.isEmpty(dtos)) {
            headEx.append("参数不能为空");
            exMap.put("headEx", headEx);
        }
        if (exMap.isEmpty()) {
            ArrayList<OutboundNoticeHeader> insertHeads = Lists.newArrayList();
            ArrayList<OutboundNoticeLine> insertLines = Lists.newArrayList();
            ArrayList<ItfImplogHeader> insertHeadLogs = Lists.newArrayList();
            ArrayList<ItfImplogLine> insertLineLogs = Lists.newArrayList();
            for (int i = 0; i < dtos.size(); i++) {
                OutboundNoticeParamDTO dto = dtos.get(i);
                //插入日志
                ItfImplogHeader implogHeader = new ItfImplogHeader();
                implogHeader.setId(snowFlakeId.nextId());
                implogHeader.setDataContent(JSONObject.toJSONString(dto));
                implogHeader.setImportTime(new Date());
                implogHeader.setStatus(TableStatusEnum.STATUS_10.getCode());
                implogHeader.setType(TableStatusEnum.STATUS_10.getCode());
                implogHeader.setUserDef9("interface_SaveOutboundNoticeHead");
                insertHeadLogs.add(implogHeader);

                checkHead(dto, headEx, i);
                //校验头重复性
                EntityWrapper<OutboundNoticeHeader> wrapper = new EntityWrapper<>();
                wrapper.eq("owner_order_no", dto.getOwnerOrderNo())//货主单号
                        .eq("source_key", dto.getSourceKey());//来源唯一键
                Integer count = baseMapper.selectCount(wrapper);
                if (count > 0) {
                    headEx.append("第")
                            .append(i + 1)
                            .append("行,已经在wms存在!");
                }
                //保存头
                OutboundNoticeHeader header = new OutboundNoticeHeader();
                if (StringUtils.isBlank(headEx)) {
                    BeanUtils.copyProperties(dto, header);
                    header.setNoticeNo(iBusinessDocNumberService.getOutboundNoticeNo());
                    header.setOutboundSumQty(new BigDecimal(0));
                    header.setLogHeaderId(implogHeader.getId());
                    header.setStatus(TableStatusEnum.STATUS_10.getCode());
                    header.setId(snowFlakeId.nextId());
                    insertHeads.add(header);
                } else {
                    exMap.put("headEx", headEx);
                }

                List<OutboundNoticeLineParamDTO> lines = dto.getLines();
                for (int j = 0; j < lines.size(); j++) {
                    //记录日志line
                    ItfImplogLine implogLine = new ItfImplogLine();
                    implogLine.setId(snowFlakeId.nextId());
                    implogLine.setHeaderId(implogHeader.getId());
                    implogLine.setSeq(String.valueOf(implogLine.getId()));
                    implogLine.setUserDef9("interface_saveOutboundNoticeLine");
                    insertLineLogs.add(implogLine);

                    OutboundNoticeLineParamDTO lineDTO = lines.get(j);
                    checkLine(lineEx, lineDTO, j);
                    //校验通过
                    if (StringUtils.isBlank(headEx)
                            && StringUtils.isBlank(lineEx)) {
                        //重复性校验
                        EntityWrapper<OutboundNoticeLine> lineWrapper = new EntityWrapper<>();
                        lineWrapper.eq("owner_order_no", lineDTO.getLineOwnerOrderNo())//货主单号
                                .eq("lot_no0", lineDTO.getLotNo0())//订单号-->波次
                                .eq("lot_no1", lineDTO.getLotNo1());//车架号
                        Integer lineCount = noticeLineService.selectCount(lineWrapper);
                        if (lineCount > 0) {
                            lineEx.append("第:")
                                    .append(j + 1)
                                    .append("行,通知单明细已经在wms存在!");
                        }
                    }
                    if (StringUtils.isNotBlank(lineEx)) {
                        exMap.put("lineEx", lineEx);
                    }
                    //所有校验通过--新增保存
                    if (StringUtils.isBlank(headEx)
                            && StringUtils.isBlank(lineEx)) {
                        OutboundNoticeLine line = new OutboundNoticeLine();
                        BeanUtils.copyProperties(lineDTO, line);
                        line.setId(snowFlakeId.nextId());
                        line.setHeaderId(header.getId());
                        line.setOwnerId(lineDTO.getLineOwnerId());
                        line.setOwnerOrderNo(lineDTO.getLineOwnerOrderNo());
                        line.setSeq(String.valueOf(line.getId()));
                        line.setOutboundQty(new BigDecimal(0));
                        line.setLogLineId(implogLine.getId());
                        line.setStatus(TableStatusEnum.STATUS_10.getCode());
                        insertLines.add(line);
                    }
                }
            }
            //数据插入 日志   业务数据
            insertLogs(insertHeadLogs, insertLineLogs);
            //标准接口不支持部分保存
            if (exMap.isEmpty()) {
                if (CollectionUtils.isNotEmpty(insertHeads) && CollectionUtils.isNotEmpty(insertLines)) {
                    insertBatch(insertHeads);
                    noticeLineService.insertBatch(insertLines);
                }
            }

        }
        return exMap;
    }

    @Override
    public Page<OutNoticeListResultDTO> queryOutboundNotice(Page<OutNoticeListResultDTO> page) {
        Wrapper<OutNoticeListResultDTO> ew = buildCondition(page.getCondition());
        List<OutNoticeListResultDTO> dtoList = this.baseMapper.selectNoticeListByParams(page, ew);
        page.setRecords(dtoList);
        return page;
    }

    /**
     * 出库通知导出
     */
    @Override
    public List<OutNoticeListResultDTO> queryExportONData(Map<String, String> condition) {
        if (condition == null || condition.isEmpty()) {
            throw new BaseException("参数不能为空");
        }
        if (StringUtils.isBlank(condition.get("houseId"))) {
            throw new BaseException("仓库id不能为空");
        }
        EntityWrapper<OutNoticeListResultDTO> ew = new EntityWrapper<>();
        if (StringUtils.isNotBlank(condition.get("status"))) {
            ew.eq("noticeLineStatus", condition.get("status"));
        }
        if (StringUtils.isNotBlank(condition.get("lotNo1"))) {
            ew.like("lot_no1", condition.get("lotNo1"));
        }
        if (StringUtils.isNotBlank(condition.get("ownerId"))) {
            ew.like("owner_id", condition.get("ownerId"));
        }
        if (StringUtils.isNotBlank(condition.get("ownerOrderNo"))) {
            ew.like("owner_order_no", condition.get("ownerOrderNo"));
        }
        ew.eq("store_house_id", condition.get("houseId"));
        ew.eq("in_store_house_id", condition.get("houseId"));
        ew.orderBy("noticeLineId", false);
        return baseMapper.selectExportONData(ew);
    }

    private Wrapper<OutNoticeListResultDTO> buildCondition(Map<String, Object> condition) {
        Wrapper<OutNoticeListResultDTO> ew = new EntityWrapper<>();
        if (condition.containsKey("houseId") && Objects.nonNull(condition.get("houseId"))) {
            ew.eq("store_house_id", condition.get("houseId").toString());
            ew.eq("in_store_house_id", condition.get("houseId").toString());
        }
        if (condition.containsKey("status") && Objects.nonNull(condition.get("status"))) {
            ew.eq("noticeLineStatus", condition.get("status").toString());
        } else {
            ew.ne("noticeLineStatus", TableStatusEnum.STATUS_50.getCode());
        }
        if (condition.containsKey("ownerId") && Objects.nonNull(condition.get("ownerId"))) {
            ew.like("owner_id", condition.get("ownerId").toString());
        }
        if (condition.containsKey("ownerOrderNo") && Objects.nonNull(condition.get("ownerOrderNo"))) {
            ew.like("owner_order_no", condition.get("ownerOrderNo").toString());
        }
        if (condition.containsKey("shipmentStartDate") && Objects.nonNull(condition.get("shipmentStartDate"))) {
            ew.ge("shipment_time", condition.get("shipmentStartDate"));
        }
        if (condition.containsKey("shipmentEndDate") && Objects.nonNull(condition.get("shipmentEndDate"))) {
            ew.le("shipment_time", condition.get("shipmentEndDate"));
        }
        if (Objects.nonNull(condition.get("startDate")) && StringUtils.isNotEmpty((String) condition.get("startDate"))) {
            ew.ge("outbound_modified", condition.get("startDate").toString());
        }
        if (Objects.nonNull(condition.get("endDate")) && StringUtils.isNotEmpty((String) condition.get("endDate"))) {
            ew.le("outbound_modified", condition.get("endDate").toString());
        }
        if (condition.containsKey("lotNo1") && Objects.nonNull(condition.get("lotNo1"))) {
            String vin = condition.get("lotNo1").toString();
            /*String[] split = vin.split(",");
            List<String> vins = Arrays.asList(split);*/
            List<String> vins = Arrays.asList(CommonMethod.setVins(vin));
            ew.andNew().in("lot_no1", vins).or().like("lot_no1", vin);
        }
        ew.orderBy("noticeLineId", false);
        return ew;
    }

    public List<OutboundNoticeHeaderDTO> selectHeaderList(Long houseId, String status, Integer size, Integer current) {
        try {
            EntityWrapper<OutboundNoticeHeaderDTO> ew = new EntityWrapper<>();
            ew.eq("store_house_id", houseId).eq("status", status);
            Page<OutboundNoticeHeaderDTO> page = new Page<>(current, size);

            List<OutboundNoticeHeaderDTO> outboundNoticeHeaders = this.baseMapper.queryNoticePage(page, ew);
            for (OutboundNoticeHeaderDTO outboundNoticeHeader :
                    outboundNoticeHeaders) {
                if (Objects.isNull(outboundNoticeHeader.getExpectSumQty()))
                    outboundNoticeHeader.setExpectSumQty(new BigDecimal(0));
                if (Objects.isNull(outboundNoticeHeader.getOutboundSumQty()))
                    outboundNoticeHeader.setOutboundSumQty(new BigDecimal(0));
            }
            return outboundNoticeHeaders;
        } catch (Exception e) {
            LOGGER.error("Service:\t" + e.toString());
            throw new BaseException("查询列表出现错误");
        }
    }

    public OutboundNoticeHeaderDTO selectHeaderDetail(Long houseId, Long id) {
        try {
            EntityWrapper<OutboundNoticeHeaderDTO> ew = new EntityWrapper<>();
            ew.eq("id", id).eq("store_house_id", houseId);
            OutboundNoticeHeaderDTO outboundNoticeHeader = this.baseMapper.getNotice(houseId, id);
            if (!Objects.isNull(outboundNoticeHeader)) {
                outboundNoticeHeader.setDriverMess((Strings.isNullOrEmpty(outboundNoticeHeader.getDriverName()) ? "" : outboundNoticeHeader.getDriverName()) + "\t" +
                        (Strings.isNullOrEmpty(outboundNoticeHeader.getDriverPhone()) ? "" : outboundNoticeHeader.getDriverPhone()));
                if (Strings.isNullOrEmpty(outboundNoticeHeader.getDriverName()))
                    outboundNoticeHeader.setDriverName("未登记");
                List<OutboundNoticeDTO> noticeDTOS = outboundNoticeLineService.selectOutboundByHeadId(outboundNoticeHeader.getId(), houseId);
                outboundNoticeHeader.setOutboundNoticeLines(noticeDTOS);
            }
            return outboundNoticeHeader;
        } catch (Exception e) {
            LOGGER.error("Service:\t" + e.toString());
            throw new BaseException("查询详情出现错误");
        }
    }


    @Override
    @Transactional
    public boolean insertOutboundNotice(OutboundNoticeHeader outboundNoticeHeader) {
        if (Objects.isNull(outboundNoticeHeader.getId())) outboundNoticeHeader.setId(snowFlakeId.nextId());
        for (OutboundNoticeLine outboundNoticeLine : outboundNoticeHeader.getOutboundNoticeLineList()) {
            outboundNoticeLine.setHeaderId(outboundNoticeHeader.getId());
            if (Objects.isNull(outboundNoticeLine.getId())) outboundNoticeLine.setId(snowFlakeId.nextId());
        }
        List<OutboundNoticeLine> outboundNoticeLines = outboundNoticeHeader.getOutboundNoticeLineList();
        if(CollectionUtils.isEmpty(outboundNoticeLines)){
            return false;
        }
        return insert(outboundNoticeHeader) && insertoutboundLineData(outboundNoticeLines);
    }

    private boolean insertoutboundLineData (List<OutboundNoticeLine> outboundNoticeLines) {
        try {
            for (OutboundNoticeLine outboundNoticeLine : outboundNoticeLines) {
                outboundNoticeLineService.insert(outboundNoticeLine);
            }
            return true;
        } catch (Exception e) {
            LOGGER.error("批量插入出库明细异常{}", e.getMessage());
            return false;
        }
    }

    @Override
    @Transactional
    public boolean updateStatus (Long noticeId, Long noticeLineId) {
        BigDecimal inboundQty = BigDecimal.ZERO;
        //更新明细出库状态
        outboundNoticeLineService.updateOutboundStatus(noticeId,noticeLineId);
        EntityWrapper<OutboundNoticeLine> ew = new EntityWrapper<>();
        ew.eq("header_id", noticeId);
        List<OutboundNoticeLine> outboundNoticeLines = outboundNoticeLineService.selectList(ew);

        for (OutboundNoticeLine outboundNoticeLine : outboundNoticeLines) {
            inboundQty = inboundQty.add(outboundNoticeLine.getOutboundQty());
        }

        String status = judgeStatus(outboundNoticeLines);
        baseMapper.updateStatus(noticeId, status, inboundQty); //更新头的状态
        return true;

    }

    private String judgeStatus(List<OutboundNoticeLine> outboundNoticeLines) {
        Boolean outboundNot = false;
        Boolean outboundAll = false;

        for (OutboundNoticeLine outNoticeLine : outboundNoticeLines) {
            if (Status.Outbound.PART.equals(outNoticeLine.getStatus())) { //部分出库直接返回
                return Status.Inbound.PART;
            }

            if (Status.Outbound.NOT.equals(outNoticeLine.getStatus())) {  //未出库
                outboundNot = true;
            }

            if (Status.Outbound.ALL.equals(outNoticeLine.getStatus())) {  //全部出库
                outboundAll = true;
            }
        }

        if (outboundNot && outboundAll) {   //明细中存在未出库和全部出库则返回部分出库
            return Status.Outbound.PART;
        } else if (!outboundNot && outboundAll) { //明细中不存在未出库且全部已出库则返回全部出库
            return Status.Outbound.ALL;
        } else if (outboundNot && !outboundAll) {//明细全部未出库且非全部出库则返回未入库
            return Status.Outbound.NOT;
        }
        return Status.Outbound.NOT;
    }

    private void insertLogs(ArrayList<ItfImplogHeader> insertHeadLogs,
                            ArrayList<ItfImplogLine> insertLineLogs) {
        if (CollectionUtils.isNotEmpty(insertHeadLogs)) {
            new Thread(() -> {
                try {
                    implogHeaderService.insertBatch(insertHeadLogs);
                } catch (Exception e) {
                    LOGGER.error("OutboundNoticeHeaderServiceImpl.saveOutboundNotice insert headLog error:{}", e);
                }
            }).start();
        }
        if (CollectionUtils.isNotEmpty(insertLineLogs)) {
            new Thread(() -> {
                try {
                    implogLineService.insertBatch(insertLineLogs);
                } catch (Exception e) {
                    LOGGER.error("OutboundNoticeHeaderServiceImpl.saveOutboundNotice insert lineLog error:{}", e);
                }
            }).start();
        }
    }

    private void checkLine(StringBuilder lineEx, OutboundNoticeLineParamDTO lineDTO, int j) {
        String lineSourceKey = lineDTO.getLineSourceKey();
        String lineSourceNo = lineDTO.getLineSourceNo();
        String lineOwnerId = lineDTO.getLineOwnerId();
        String lineOwnerOrderNo = lineDTO.getLineOwnerOrderNo();
        String lotNo0 = lineDTO.getLotNo0();//订单号
        BigDecimal expectQty = lineDTO.getExpectQty();
        String lotNo1 = lineDTO.getLotNo1();//车架号
        if (StringUtils.isBlank(lineSourceKey)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,行来源唯一键 不能为空!");
        }
        if (StringUtils.isBlank(lineSourceNo)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,行来源单据号 不能为空!");
        }
        if (StringUtils.isBlank(lineOwnerId)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,货主 不能为空!");
        }
        if (StringUtils.isBlank(lineOwnerOrderNo)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,货主单号 不能为空!");
        }
        if (Objects.isNull(expectQty)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,预计入库数量 不能为空!");
        }
        if (StringUtils.isBlank(lotNo0)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,订单号 不能为空!");
        }
        if (StringUtils.isBlank(lotNo1)) {
            lineEx.append("第:")
                    .append(j + 1)
                    .append("行,车架号 不能为空!");
        }
    }

    private void checkHead(OutboundNoticeParamDTO dto,
                           StringBuilder headEx,
                           int i) {
        Long storeHouseId = dto.getStoreHouseId();
        String ownerId = dto.getOwnerId();
        String ownerOrderNo = dto.getOwnerOrderNo();
        BigDecimal expectSumQty = dto.getExpectSumQty();
        String sourceKey = dto.getSourceKey();
        String sourceNo = dto.getSourceNo();
        Integer lineCount = dto.getLineCount();
        if (Objects.isNull(storeHouseId)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,收货仓库id 不能为空!");
        }
        if (StringUtils.isBlank(ownerId)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,货主id 不能为空!");
        }
        if (StringUtils.isBlank(ownerOrderNo)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,货主单号 不能为空!");
        }
        if (Objects.isNull(expectSumQty)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,预计入库数量 不能为空!");
        }
        if (StringUtils.isBlank(sourceKey)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,来源唯一键 不能为空!");
        }
        if (StringUtils.isBlank(sourceNo)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,来源单据号 不能为空!");
        }
        if (Objects.isNull(lineCount)) {
            headEx.append("第")
                    .append(i + 1)
                    .append("行,明细行数 不能为空!");
        }
    }


}
